package implementation1.app;

import exceptions.StreamException;
import interfaces.app.IStream;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A final class with tool methods.
 * Created: 17.11.11
 *
 * @author Jan Svab
 */
public final class Global
{
    /**
     * Logger for logging errors.
     */
    public static Logger logger = Logger.getLogger("main_log");

    /**
     * Sets output of the logger into file
     */
    public static void setLoggerToFile()
    {
        Handler handler = null;
        try
        {
            handler = new FileHandler("main_log", 1000, 1000);

        } catch (IOException e)
        {
            e.printStackTrace();
        }
        logger.addHandler(handler);
        //logger.setUseParentHandlers(false);  //output from logger doesn't get into console
    }

    /**
     * Creates and optimizes the absolute path to some file.
     *
     * @param actualDir     a absolute path to actual selected directory
     * @param requestedFile a path(absolute or relative) to some file
     * @return File object with the absolute path to required file
     */
    public static File getFileWithAbsPath(String actualDir, String requestedFile)
    {
        File actualDirFile = new File(actualDir);

        if (requestedFile == null || requestedFile.length() < 1
            || (requestedFile.length() == 1 && requestedFile.charAt(0) == File.separatorChar))
        {
            return actualDirFile;
        }

        //checking if path doesn't contains 'C:', 'k:', ...
        if (requestedFile.length() == 2 && ((requestedFile.charAt(0) >= 'a' && requestedFile.charAt(0) <= 'z')
                                            || (requestedFile.charAt(0) >= 'A' && requestedFile.charAt(0) <= 'Z'))
            && (requestedFile.charAt(1) == ':'))
        {
            requestedFile = requestedFile.toUpperCase() + File.separatorChar;

            for (File rootDir : File.listRoots())
            {
                if (rootDir.getPath().equals(requestedFile))
                {
                    return rootDir;
                }
            }
        }

        File reqFile = new File(requestedFile);

        if (reqFile.isAbsolute())
        {
            return reqFile;
        }

        if (reqFile.getPath().charAt(0) == File.separatorChar)
        {
            requestedFile = requestedFile.substring(1);
        }

        String actualDirAbsPathEdit = actualDirFile.getAbsolutePath();
        if (actualDirAbsPathEdit.charAt(actualDirAbsPathEdit.length() - 1) == File.separatorChar)
        {
            return new File(actualDir + requestedFile);
        }
        else
        {
            return new File(actualDir + File.separatorChar + requestedFile);
        }
    }

    /**
     * Optimizes the absolute path to some file. Removes '.' and '..' from path.
     *
     * @param absPath the absolute path to some file
     * @return the optimized absolute path to some file
     */
    public static File normalizePath(File absPath)
    {
        String pathStr = absPath.getAbsolutePath();
        if (pathStr.lastIndexOf(File.separator + ".") == pathStr.length() - 2 ||
            pathStr.lastIndexOf(File.separator + "..") == pathStr.length() - 3) //for better replacing '/.' on end
        {
            pathStr += File.separator;
        }
        //removing '.' from path
        while (pathStr.contains(File.separator + "." + File.separator))
        {
            pathStr = pathStr.replace(File.separator + "." + File.separator, File.separator);
        }

        //removing '..'
        String separator = File.separator;
        if (File.separator.equals("\\"))
        {
            separator = "\\\\";
        }

        //split on parts of path
        List<String> splitPath = new ArrayList<String>();
        splitPath.addAll(Arrays.asList(pathStr.split(separator)));


        for (int index = 0; index < splitPath.size(); index++)
        {
            if (splitPath.get(index).equals("..")) //if part contains '..' => removing this part and part before
            {
                if (index <= 1) //in absolute path before the root isn't nothing => error
                {
                    return null;
                }

                splitPath.remove(index);
                splitPath.remove(--index);
                index--;
            }
        }

        //building of new path
        String newPath = "";

        for (String pathPart : splitPath)
        {
            if (!newPath.equals(""))
            {
                newPath += File.separator + pathPart;
            }
            else
            {
                newPath += pathPart.toUpperCase();
            }
        }

        //path is only 'c:', 'D:', ... => adding the file separator on end
        if (splitPath.size() == 1)
        {
            newPath += File.separator;
        }

        return new File(newPath);
    }

    /**
     * Closes a stream quietly without exception.
     * If close() method thrown exception, it is write into logger.
     *
     * @param stream the stream for closing
     */
    public static void closeStreamQuietly(IStream stream)
    {
        if (stream == null || !stream.isOpen())
        {
            return;
        }

        try
        {
            stream.close();
        } catch (StreamException e)
        {
            logger.log(Level.SEVERE, "Closing of the stream: " + e.getMessage());
        }
    }
}
